package com.tourscool.springboot.starter.inquiry.core;

import com.tourscool.springboot.starter.inquiry.utils.NetworkUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Cedric
 * @date 2020/10/26 16:01
 * @description 获取控制器方法列表
 */
public final class ControllerInterfaceUtils {

    public static List<RequestMethodItem> getControllerMethodList(ApplicationContext applicationContext) {

        //请求url和处理方法的映射
        List<RequestMethodItem> requestMethodItemList = new ArrayList<>();

        WebApplicationContext appContext = (WebApplicationContext) applicationContext;

        if (null == appContext) {
            return requestMethodItemList;
        }

        String serverName = NetworkUtils.getIp().getIP();
        Environment environment = appContext.getBean(Environment.class);
        String pServiceName = environment.getProperty("spring.application.name", "unknown");

        //获取所有的RequestMapping
        Map<String, HandlerMapping> allRequestMappings = BeanFactoryUtils.beansOfTypeIncludingAncestors(appContext,
                HandlerMapping.class, true, false);

        for (HandlerMapping handlerMapping : allRequestMappings.values()) {
            //本项目只需要RequestMappingHandlerMapping中的URL映射
            if (handlerMapping instanceof RequestMappingHandlerMapping) {
                RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) handlerMapping;
                Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
                for (Map.Entry<RequestMappingInfo, HandlerMethod> requestMappingInfoHandlerMethodEntry : handlerMethods.entrySet()) {
                    // 获取实体对象
                    RequestMappingInfo requestMappingInfo = requestMappingInfoHandlerMethodEntry.getKey();
                    HandlerMethod mappingInfoValue = requestMappingInfoHandlerMethodEntry.getValue();

                    // 获取请求方式GET/POST/PUT/DELETE（如果@RequestMapping中没有写具体的请求方式则获取不到哦）
                    RequestMethodsRequestCondition methodCondition = requestMappingInfo.getMethodsCondition();
                    Iterator<RequestMethod> methodIterator = methodCondition.getMethods().iterator();
                    String requestType = methodIterator.hasNext() ? methodIterator.next().name() : "";
                    // 获取请求的URL
                    PatternsRequestCondition patternsCondition = requestMappingInfo.getPatternsCondition();
                    Iterator<String> iterator = patternsCondition.getPatterns().iterator();
                    String requestUrl = iterator.hasNext() ? iterator.next() : "";
                    //获取接口所在的类名,方法名,参数名
                    String controllerName = mappingInfoValue.getBeanType().getName();
                    String requestMethodName = mappingInfoValue.getMethod().getName();
                    Class<?>[] methodParamTypes = mappingInfoValue.getMethod().getParameterTypes();
                    Class<?> returnType = mappingInfoValue.getMethod().getReturnType();
                    RequestMethodItem requestMethodItem = new RequestMethodItem(serverName, pServiceName, controllerName, requestMethodName,
                            requestType, requestUrl, pServiceName, Arrays.stream(methodParamTypes).map(Class::getName).collect(Collectors.joining(",")), returnType.getName());
                    requestMethodItemList.add(requestMethodItem);
                }
                break;
            }
        }

        return requestMethodItemList;
    }
}
